package com.gz.common.mongodb.dao;

import com.gz.common.mongodb.support.MongoGroup;
import com.gz.common.mongodb.utils.Mongo;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.lang.Nullable;

import java.util.List;

/**
 * 提供分组、聚合查询
 *
 * @param <Model>
 */
public interface MongoGroupMapper<Model> extends MongoGetTClass<Model> {

    /**
     * 条件计数
     *
     * @param query
     * @return
     */
    default long count(Query query) {
        return Mongo.mongoTemplate().count(query, this.getTClass());
    }

    /**
     * 聚合查询
     *
     * @param criteria    查询条件
     * @param groupcolumn 分组字段
     * @param mongoGroup  聚合函数
     * @param resultType  返回List<T> T的类型
     * @param <T>
     * @return
     */
    default <T> List<T> group(Criteria criteria, List<String> groupcolumn, MongoGroup mongoGroup, @Nullable Sort sort, Class<T> resultType) {
        // 查询条件
        MatchOperation match = Aggregation.match(criteria);

        // 构建聚合函数字段、同时添加到返回字段
        mongoGroup.build(groupcolumn);
        GroupOperation group = mongoGroup.getGroup();
        ProjectionOperation projection = mongoGroup.getProjection();

        Aggregation aggregation = (sort == null) ?
                Aggregation.newAggregation(match, group, projection) :
                Aggregation.newAggregation(match, group, projection, Aggregation.sort(sort));

        // 聚合查询
        AggregationResults<T> aggregate = Mongo.mongoTemplate().aggregate(aggregation, this.getTClass(), resultType);
        return aggregate.getMappedResults();
    }

    /**
     * 聚合查询， 返回List<Model>
     *
     * @param criteria
     * @param groupClounm
     * @param mongoGroup
     * @return
     */
    default List<Model> group(Criteria criteria, List<String> groupClounm, MongoGroup mongoGroup, @Nullable Sort sort) {
        return group(criteria, groupClounm, mongoGroup, sort, this.getTClass());
    }
}
